﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;


namespace EBookStore.UnitTests
{
    [TestFixture]
    [Category("Full Workflow")]
    public class Test_Workflow
    {

        Management.BookStore store = null;
                   
        Users.User userA = null;
        Users.User userB = null;
        Users.User userC = null;
        Users.User clerk = null;

        [SetUp]
        public void init()
        {
            store = Management.BookStore.Instance;
            store.PublishersMgr.AddPublishers(ObjectsGenerator.GeneratePublishers(100));
            store.CatalogMgr.AddBooks(ObjectsGenerator.GenerateBooks(100, store.PublishersMgr.Publishers.ToArray()));

            clerk = new Users.Clerk("1", "1", "clerk_Name", "clerk_ln");
            userA = new Users.Customer("2", "2", "customer_A", "customerA_ln", "addressA");
            userB = new Users.Customer("3", "2", "customer_B", "customerB_ln", "addressB");
            userC = new Users.Customer("4", "4", "customer_C", "customerC_ln", "addressC");
                       
        }

        [TearDown]
        public void clear()
        {
            store.PublishersMgr.Clear();
            store = null;         
           
            clerk = null;
            userA = null;
            userB = null;
            userC = null;

        }


        [TestCase]
        public void MainWorkFlow()
        {                                   
                                                            
            // add users to DB
            store.UsersMgr.AddUser(clerk);
            store.UsersMgr.AddUser(userA);
            store.UsersMgr.AddUser(userB);
            store.UsersMgr.AddUser(userC);

            // now all users can pass login.
            store.UsersMgr.Login(clerk.Login, clerk.Password);
            store.UsersMgr.Login(userA.Login, userA.Password);
            store.UsersMgr.Login(userB.Login, userB.Password);
            store.UsersMgr.Login(userC.Login, userC.Password);
            /*************************************************************************/
                           
            
            Books.Book[] books = store.CatalogMgr.ToArray();

            List<Orders.SingleBookOrder> so =  new List<Orders.SingleBookOrder>();
            so.Add( new Orders.SingleBookOrder(books[0],20));
            so.Add( new Orders.SingleBookOrder(books[1],2));
            so.Add( new Orders.SingleBookOrder(books[2],3));
            so.Add(new Orders.SingleBookOrder(books[3], 4));

            Orders.Order orderUserA = store.OrdersMgr.CreateOrder(userA, Orders.eOrderVia.WWW, ObjectsGenerator.CreateCreditCardPayment(1)[0], so.ToArray());
            Orders.Order orderUserB = store.OrdersMgr.CreateOrder(userB, Orders.eOrderVia.Email, ObjectsGenerator.CreateCreditCardPayment(1)[0], so.ToArray());
            Orders.Order orderUserC = store.OrdersMgr.CreateOrder(userC, Orders.eOrderVia.Phone, ObjectsGenerator.CreateCreditCardPayment(1)[0], so.ToArray());


            // user has order --> cant be removed
            Assert.That(
                () => store.UsersMgr.RemoveUser(userC),
                Throws.Exception.TypeOf<Exception>());
            
            // check current order status - Created
            Assert.AreEqual(Orders.eOrderStatus.Charged, orderUserA.Status);

            // Exception - userA can't cancel other's user order
            Assert.That(
                () => store.OrdersMgr.CancelOrder(userA, orderUserB.ID),
                Throws.Exception.TypeOf<Exception>());


            // user has order --> can not remove him
            Assert.That(
              () => store.UsersMgr.RemoveUser(userB),
              Throws.Exception.TypeOf<Exception>());
            
            // can cancel order
            Assert.AreEqual(true, store.OrdersMgr.CancelOrder(userA, orderUserA.ID));

            // Order books from publishers
            store.OrdersMgr.OrderBooksFromPublishers();

            // emulate event of recieved books            
            store.PublishersMgr.AddBooksSuppliedByPublisher(new Orders.BookAndAmount(books[0], 20));
            store.PublishersMgr.AddBooksSuppliedByPublisher(new Orders.BookAndAmount(books[1], 2));
            store.PublishersMgr.AddBooksSuppliedByPublisher(new Orders.BookAndAmount(books[2], 3));
            store.PublishersMgr.AddBooksSuppliedByPublisher(new Orders.BookAndAmount(books[3], 4));


            
            // Recieve books from publishers
            store.OrdersMgr.RecieveBooksFromPublishers();


            // we still have user's without recieved books

            int pendingBooks = store.PublishersMgr.CountPendingBooksFromPublisher(clerk, store.PublishersMgr.GetPublisher(books[0].PublisherID));
            Assert.AreEqual(40,pendingBooks);
            
            // close all delivered orders
            store.OrdersMgr.CloseOrders();

            // Order order B still havent benn delivered fully
            Assert.True(store.OrdersMgr.CancelOrder(userB, orderUserB.ID));                

         

            // UserC want to return books --> OK
            Assert.True(store.OrdersMgr.ReturnBook(userC, orderUserC.ID, orderUserC.BookList[0].Book, 1));

           
            
        }
    }
}
